using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.ServiceModel;
using System.IO;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Saml2;
using Microsoft.IdentityModel.Configuration;
using System.ServiceModel.Security;
using System.ServiceModel.Description;
using System.Security.Cryptography.X509Certificates;
using System.Configuration;
using System.ComponentModel;
using GsmComm.PduConverter;
using GsmComm.GsmCommunication;

namespace WebRole1
{
    public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            # region ensure container exist
            //CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            //{
            //    configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
            //});
            //// get the blob connection string
            //CloudStorageAccount objStorage = CloudStorageAccount.FromConfigurationSetting("BlobConnectionString");
            //// get the client reference
            //CloudBlobClient objClient = new CloudBlobClient(objStorage.BlobEndpoint, objStorage.Credentials);
            //// Get the reference to container
            //CloudBlobContainer objContainer = objClient.GetContainerReference("mycontainer");
            //try
            //{
            //    // Create the container if it does not exist
            //    objContainer.CreateIfNotExist();
            //}
            //catch (Exception) { }
            ////// Get the reference to container
            ////objContainer = objClient.GetContainerReference("face");

            ////// Create the container if it does not exist
            ////objContainer.CreateIfNotExist();

            # endregion

            #region azure appfabric access service control
            ServiceHost rpHost = CreateWcfServiceHost();


            rpHost.Open();


            //rpHost.Close();

            //rpHost.Abort();

            #endregion

            //set up backgroundworker
            BackgroundWorker bgWorker = new BackgroundWorker();
            bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
            bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
            bgWorker.WorkerSupportsCancellation = true;

            //run background worker
            bgWorker.RunWorkerAsync(500);

            return base.OnStart();
        }

        void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            CommSetting.Comm_Port = 6;
            CommSetting.Comm_BaudRate = 9600;
            CommSetting.Comm_TimeOut = 300;

            CommSetting.comm = new GsmComm.GsmCommunication.GsmCommMain(6, 9600, 2000);
            CommSetting.comm.MessageReceived += new MessageReceivedEventHandler(comm_MessageReceived);
            try
            {
                CommSetting.comm.Open();
                //lblTest.Text = "";
            }
            catch
            {
                //lblTest.Text = "Please wait for 5 sec and try again";
            }
            string storage = GetMessageStorage();

            try
            {
                // Read all SMS messages from the storage

                DecodedShortMessage[] messages = CommSetting.comm.ReadMessages(PhoneMessageStatus.All, storage);
                foreach (DecodedShortMessage message in messages)
                {
                    Output(string.Format("Message status = {0}, Location = {1}/{2}",
                    StatusToString(message.Status), message.Storage, message.Index));
                    ShowMessage(message.Data);
                    if (!(message.ToString().Equals("")) && docHP != null)
                        SendMessage(Send, docHP); // contact number need to change
                    CommSetting.comm.DeleteMessage(0, storage);
                    Output("");
                }
                Output(string.Format("{0,9} messages read.", messages.Length.ToString()));
                Output("");
            }
            catch (Exception ex)
            {
                //txtOutput.Text = ex.ToString();
            }
            try
            {
                CommSetting.comm.Close();
            }
            catch (Exception ex)
            {

            }
        }

        void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //throw new NotImplementedException();

            //Dispatcher.BeginInvoke((Action) =>
            //{

            //});
        }

        #region sms
        taraService svc = new taraService();
        public String Send = "";
        int docHP;
        string orignial;
        string patientName;

        private void comm_MessageReceived(object sender, GsmComm.GsmCommunication.MessageReceivedEventArgs e)
        {
            MessageReceived();
        }
        private void MessageReceived()
        {
            string storage = GetMessageStorage();

            DecodedShortMessage[] messages = CommSetting.comm.ReadMessages(PhoneMessageStatus.ReceivedUnread, storage);
            foreach (DecodedShortMessage message in messages)
            {
                Output(string.Format("Message status = {0}, Location = {1}/{2}",
                StatusToString(message.Status), message.Storage, message.Index));
                ShowMessage(message.Data);
                Output("");
            }

            Output(string.Format("{0,9} messages read.", messages.Length.ToString()));
            Output("");
        }
        private string GetMessageStorage()
        {
            string storage = string.Empty;
            storage = PhoneStorageType.Sim;

            if (storage.Length == 0)
                throw new ApplicationException("Unknown message storage.");
            else
                return storage;
        }
        public static void Output(string text)
        {
            //txtOutput.Text += text;
            //txtOutput.Text += "\r\n";
        }
        private string StatusToString(PhoneMessageStatus status)
        {
            // Map a message status to a string
            string ret;
            switch (status)
            {
                case PhoneMessageStatus.All:
                    ret = "All";
                    break;
                case PhoneMessageStatus.ReceivedRead:
                    ret = "Read";
                    break;
                case PhoneMessageStatus.ReceivedUnread:
                    ret = "Unread";
                    break;
                case PhoneMessageStatus.StoredSent:
                    ret = "Sent";
                    break;
                case PhoneMessageStatus.StoredUnsent:
                    ret = "Unsent";
                    break;
                default:
                    ret = "Unknown (" + status.ToString() + ")";
                    break;
            }
            return ret;
        }

        private void ShowMessage(SmsPdu pdu)
        {
            if (pdu is SmsSubmitPdu)
            {
                // Stored (sent/unsent) message
                SmsSubmitPdu data = (SmsSubmitPdu)pdu;
                Output("SENT/UNSENT MESSAGE");
                Output("Recipient: " + data.DestinationAddress);
                Output("Message text: " + data.UserDataText);
                Output("-------------------------------------------------------------------");
                return;
            }
            if (pdu is SmsDeliverPdu)
            {
                // Received message
                SmsDeliverPdu data = (SmsDeliverPdu)pdu;
                Output("RECEIVED MESSAGE");
                Output("Sender: " + data.OriginatingAddress);
                Output("Sent: " + data.SCTimestamp.ToString());
                Output("Message text: " + data.UserDataText);
                Output("-------------------------------------------------------------------");
                orignial = data.OriginatingAddress.Replace("+65", "");
                KeyValuePair<string, string> value = svc.retrieveDoctorNumber(orignial);
                docHP = Convert.ToInt32(value.Value);
                patientName = value.Key;
                Send = "Patient: " + patientName + "," + data.OriginatingAddress;
                Send += "\n" + data.UserDataText;
                return;
            }
            if (pdu is SmsStatusReportPdu)
            {
                // Status report
                SmsStatusReportPdu data = (SmsStatusReportPdu)pdu;
                Output("STATUS REPORT");
                Output("Recipient: " + data.RecipientAddress);
                Output("Status: " + data.Status.ToString());
                Output("Timestamp: " + data.DischargeTime.ToString());
                Output("Message ref: " + data.MessageReference.ToString());
                Output("-------------------------------------------------------------------");
                return;
            }
            Output("Unknown message type: " + pdu.GetType().ToString());
        }

        private void SendMessage(string text, int number)
        {
            try
            {
                // Send an SMS message
                SmsSubmitPdu pdu;

                // The straightforward version
                pdu = new SmsSubmitPdu(text.ToString(), number.ToString(), "");  // "" indicate SMSC No

                // Send the same message multiple times if this is set
                int times = 1;

                // Send the message the specified number of times
                for (int i = 0; i < times; i++)
                {
                    CommSetting.comm.SendMessage(pdu);
                    Output2("Message {0} of {1} sent.", i + 1, times);
                    Output2("");
                }
            }
            catch (Exception ex)
            {
                //lblTest.Text = ex.ToString();
            }
        }

        public static void SendMessageToTechnicalSupport(string text, int number, string patientHPNum)
        {
            CommSetting.Comm_Port = 6;
            CommSetting.Comm_BaudRate = 9600;
            CommSetting.Comm_TimeOut = 300;

            CommSetting.comm = new GsmComm.GsmCommunication.GsmCommMain(6, 9600, 2000);
            //CommSetting.comm.MessageReceived += new MessageReceivedEventHandler(comm_MessageReceived);
            try
            {
                CommSetting.comm.Open();
                //lblTest.Text = "";
            }
            catch
            {
                //lblTest.Text = "Please wait for 5 sec and try again";
            }
            try
            {
                // Send an SMS message
                SmsSubmitPdu pdu;
                string x = patientHPNum.ToString() + " " + text.ToString();
                // The straightforward version
                pdu = new SmsSubmitPdu(x.ToString(), number.ToString(), "");  // "" indicate SMSC No

                // Send the same message multiple times if this is set
                int times = 1;

                // Send the message the specified number of times
                for (int i = 0; i < times; i++)
                {
                    CommSetting.comm.SendMessage(pdu);
                    WebRole.Output2("Message {0} of {1} sent.", i + 1, times);
                    Output2("");
                }
            }
            catch (Exception ex)
            {
                //lblTest.Text = ex.ToString();
            }
        }

        public static void SendMessageToDoctorSupport(string text, int number, string patientHPNum, string patientName)
        {
            CommSetting.Comm_Port = 6;
            CommSetting.Comm_BaudRate = 9600;
            CommSetting.Comm_TimeOut = 300;

            CommSetting.comm = new GsmComm.GsmCommunication.GsmCommMain(6, 9600, 2000);
            //CommSetting.comm.MessageReceived += new MessageReceivedEventHandler(comm_MessageReceived);
            try
            {
                CommSetting.comm.Open();
                //lblTest.Text = "";
            }
            catch
            {
                //lblTest.Text = "Please wait for 5 sec and try again";
            }
            try
            {
                // Send an SMS message
                SmsSubmitPdu pdu;
                string x = patientName.ToString() + ": " + patientHPNum.ToString() + " " + text.ToString();
                // The straightforward version
                pdu = new SmsSubmitPdu(x.ToString(), number.ToString(), "");  // "" indicate SMSC No

                // Send the same message multiple times if this is set
                int times = 1;

                // Send the message the specified number of times
                for (int i = 0; i < times; i++)
                {
                    CommSetting.comm.SendMessage(pdu);
                    WebRole.Output2("Message {0} of {1} sent.", i + 1, times);
                    Output2("");
                }
            }
            catch (Exception ex)
            {
                //lblTest.Text = ex.ToString();
            }
        }

        public static void Output2(string text, params object[] args)
        {
            string msg = string.Format(text, args);
            Output(msg);
        }
        #endregion

        #region methods for acs

        public const string ServiceNamespace = "acstara";
        public const string AcsHostUrl = "accesscontrol.windows.net";

        static string AccessControlSigningCertificateFilePath = ConfigurationManager.AppSettings.Get("AccessControlSigningCertificateFilePath");

        static string ServiceAddress = "http://localhost:7100/taraService.svc";
        static string ServiceCertificateFilePath = ConfigurationManager.AppSettings.Get("ServiceCertificateFilePath");
        static string ServiceCertificatePassword = ConfigurationManager.AppSettings.Get("ServiceCertificatePassword");

        private static X509Certificate2 GetAcsSigningCertificate()
        {
            return new X509Certificate2(searchAndretrieveImage("ACS2SigningCertificate.cer"));
        }

        private static X509Certificate2 GetServiceCertificateWithPrivateKey()
        {
            return new X509Certificate2(searchAndretrieveImage("WcfServiceCertificate.pfx"), "password");
        }

        private static ServiceHost CreateWcfServiceHost()
        {
            string acsUsernameEndpoint = String.Format("https://{0}.{1}/v2/wstrust/13/username", ServiceNamespace, AcsHostUrl);

            ServiceHost rpHost = new ServiceHost(typeof(taraService));

            rpHost.Credentials.ServiceCertificate.Certificate = GetServiceCertificateWithPrivateKey();


            rpHost.AddServiceEndpoint(typeof(ItaraService),
                                       Bindings.CreateServiceBinding(acsUsernameEndpoint),
                                       ServiceAddress);


            ServiceDebugBehavior debug = rpHost.Description.Behaviors.Find<ServiceDebugBehavior>();

            // if not found - add behavior with setting turned on 

            if (debug == null)
            {
                rpHost.Description.Behaviors.Add(
                    new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
            }
            else
            {
                // make sure setting is turned ON    
                if (!debug.IncludeExceptionDetailInFaults)
                { debug.IncludeExceptionDetailInFaults = true; }
            }



            //
            // This must be called after all WCF settings are set on the service host so the
            // Windows Identity Foundation token handlers can pick up the relevant settings.
            //
            ServiceConfiguration serviceConfiguration = new ServiceConfiguration();
            // Disable certificate validation to work with sample certificates
            serviceConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;

            // Accept ACS signing certificate as Issuer.
            serviceConfiguration.IssuerNameRegistry = new X509IssuerNameRegistry(GetAcsSigningCertificate().SubjectName.Name);

            // Add the SAML 2.0 token handler.
            serviceConfiguration.SecurityTokenHandlers.AddOrReplace(new Saml2SecurityTokenHandler());

            // Add the address of this service to the allowed audiences.
            serviceConfiguration.SecurityTokenHandlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri(ServiceAddress));

            FederatedServiceCredentials.ConfigureServiceHost(rpHost, serviceConfiguration);

            return rpHost;
        }

        public static byte[] searchAndretrieveImage(string txtSearch)
        {
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
            });
            // Get the storage account reference
            CloudStorageAccount objStorage = CloudStorageAccount.FromConfigurationSetting("BlobConnectionString");
            // get the Client reference using storage blobend point
            CloudBlobClient objClient = new CloudBlobClient(objStorage.BlobEndpoint, objStorage.Credentials);
            // Get Container reference
            CloudBlobContainer objContainer = objClient.GetContainerReference("mycontainer");

            // Get the blob reference using the blob name provided in the search
            CloudBlob obj = objContainer.GetBlobReference(txtSearch);

            try
            {
                //objimg = System.Drawing.Image.FromStream(blobstream, true);

                MemoryStream ms = new MemoryStream();
                obj.DownloadToStream(ms);
                //obj.Properties.ContentType;
                return ms.ToArray();
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion
    }
}